// 版权归Go作者所有。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package jsonrpc

import (
	"encoding/json"
	"errors"
	"io"
	"net/rpc"
	"sync"
)

var errMissingParams = errors.New("jsonrpc: request body missing params")

type serverCodec struct {
	dec *json.Decoder // 用于读取JSON值
	enc *json.Encoder // 用于写入JSON值
	c   io.Closer

	// 临时工作空间
	req serverRequest

	// JSON-RPC客户端可以使用任意JSON值作为请求ID。
	// 包rpc需要uint64请求ID。
	// 我们为传入请求分配uint64序列号
	// 但将原始请求ID保存在挂起的映射中。
	// 当rpc响应时，我们使用
	// 响应中的序列号查找原始请求ID。
	mutex   sync.Mutex // 保护seq，挂起
	seq     uint64
	pending map[uint64]*json.RawMessage
}

// NewServerCodec在conn上使用JSON-rpc返回一个新的rpc.ServerCodec。
func NewServerCodec(conn io.ReadWriteCloser) rpc.ServerCodec {
	return &serverCodec{
		dec:     json.NewDecoder(conn),
		enc:     json.NewEncoder(conn),
		c:       conn,
		pending: make(map[uint64]*json.RawMessage),
	}
}

type serverRequest struct {
	Method string           `json:"method"`
	Params *json.RawMessage `json:"params"`
	Id     *json.RawMessage `json:"id"`
}

func (r *serverRequest) reset() {
	r.Method = ""
	r.Params = nil
	r.Id = nil
}

type serverResponse struct {
	Id     *json.RawMessage `json:"id"`
	Result interface{}      `json:"result"`
	Error  interface{}      `json:"error"`
}

func (c *serverCodec) ReadRequestHeader(r *rpc.Request) error {
	c.req.reset()
	if err := c.dec.Decode(&c.req); err != nil {
		return err
	}
	r.ServiceMethod = c.req.Method

	// JSON请求ID可以是任何JSON值；
	// RPC包需要uint64。翻译成
	// 内部uint64，并在侧面保存JSON。
	c.mutex.Lock()
	c.seq++
	c.pending[c.seq] = c.req.Id
	c.req.Id = nil
	r.Seq = c.seq
	c.mutex.Unlock()

	return nil
}

func (c *serverCodec) ReadRequestBody(x interface{}) error {
	if x == nil {
		return nil
	}
	if c.req.Params == nil {
		return errMissingParams
	}
	// JSON参数是数组值。
	// RPC参数为结构。
	// 暂时解组到包含struct的数组中。
	// 应该考虑使RPC更通用。
	var params [1]interface{}
	params[0] = x
	return json.Unmarshal(*c.req.Params, &params)
}

var null = json.RawMessage([]byte("null"))

func (c *serverCodec) WriteResponse(r *rpc.Response, x interface{}) error {
	c.mutex.Lock()
	b, ok := c.pending[r.Seq]
	if !ok {
		c.mutex.Unlock()
		return errors.New("invalid sequence number in response")
	}
	delete(c.pending, r.Seq)
	c.mutex.Unlock()

	if b == nil {
		// 请求无效，因此没有id。请使用JSON null。
		b = &null
	}
	resp := serverResponse{Id: b}
	if r.Error == "" {
		resp.Result = x
	} else {
		resp.Error = r.Error
	}
	return c.enc.Encode(resp)
}

func (c *serverCodec) Close() error {
	return c.c.Close()
}

// servecon在单个连接上运行JSON-RPC服务器。
// servecon阻塞，为连接提供服务，直到客户端挂断。
// 调用方通常在go语句中调用servecon。
func ServeConn(conn io.ReadWriteCloser) {
	rpc.ServeCodec(NewServerCodec(conn))
}
